Skip to content

Introduce Board._effective_promoted()#1180

Merged
niklasf merged 1 commit intomasterfrom
refactor/effective-promoted
Feb 13, 2026
Merged

Introduce Board._effective_promoted()#1180
niklasf merged 1 commit intomasterfrom
refactor/effective-promoted

Conversation

@niklasf
Copy link
Owner

@niklasf niklasf commented Feb 13, 2026

No description provided.

@niklasf niklasf force-pushed the refactor/effective-promoted branch from c471450 to 82ad2c7 Compare February 13, 2026 22:29
@niklasf niklasf merged commit 312f3bf into master Feb 13, 2026
59 checks passed
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR centralizes “which promoted markers actually matter” behind a new Board._effective_promoted() hook, so core logic (king lookup, castling-rights handling, transposition keys, and default FEN rendering) can treat promotions consistently across variants.

Changes:

  • Add Board._effective_promoted() (defaulting to BB_EMPTY) and use it throughout king/castling/status/transposition-key logic.
  • Update board_fen() so promoted=None means “auto”: mark only _effective_promoted() pieces.
  • Add variant-specific _effective_promoted() overrides (e.g., Suicide/Crazyhouse) and remove now-redundant variant overrides of board_fen() / _transposition_key().

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
chess/__init__.py Introduces _effective_promoted() in the base board and routes FEN/castling/king/status/hash logic through it.
chess/variant.py Defines variant-specific _effective_promoted() behaviors and updates variant logic to use it instead of raw promoted.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1160 to +1166
if promoted is None:
promoted_mask = self._effective_promoted()
elif promoted:
promoted_mask = self.promoted
else:
promoted_mask = BB_EMPTY
if BB_SQUARES[square] & promoted_mask:
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

board_fen() recomputes promoted_mask (and may call _effective_promoted()) inside the per-square loop. Since promoted does not change while building the string, compute promoted_mask once before iterating squares to avoid repeated work in this hot path.

Copilot uses AI. Check for mistakes.
promoted = self.has_chess960_castling_rights()
return super().board_fen(promoted=promoted)
def _effective_promoted(self) -> chess.Bitboard:
return self.kings & self.promoted if self.castling_rights else chess.BB_EMPTY
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In SuicideBoard._effective_promoted(), gating on raw self.castling_rights can mark promoted kings as “effective” even when there are no valid castling rights (e.g. after parsing an invalid FEN where clean_castling_rights() would be empty). This can make fen()/epd() output and _transposition_key() depend on a castling-rights state that would otherwise be ignored. Consider basing the condition on castling rights that survive basic validation (for example, requiring a corresponding rook on the castling-rights square) so effective promotions track actually usable castling rights.

Suggested change
return self.kings & self.promoted if self.castling_rights else chess.BB_EMPTY
return self.kings & self.promoted if self.clean_castling_rights() else chess.BB_EMPTY

Copilot uses AI. Check for mistakes.
@niklasf niklasf deleted the refactor/effective-promoted branch February 13, 2026 22:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments